#ifndef     __RT_TIME_FUTURE_H
#define     __RT_TIME_FUTURE_H

#include "./future2.h"
#include "../event/time_app.h"

namespace rt {

struct TimeoutError : public std::exception {
    using T = std::exception;
    using T::T;
};

template <typename T> class TimeoutNotify : public Notify2<T> {

public:
    void timeout() {
        this->resume();
    }

    T get() {
        if ( this->is_complete() ) {
            if constexpr (std::is_void_v<T>) {
                this->m_value.get();
            } else {
                return this->m_value.get();
            }
        } else {
            throw TimeoutError("timeout");
        }
    }
};

template <typename T> class TimeoutFuture2 {

public:
    TimeoutFuture2(int ms) : m_delay_ms(ms) {}

    std::weak_ptr<TimeoutNotify<T>> weak() { return m_notify; }

    bool await_ready() const noexcept { return m_notify->is_complete(); }
    bool await_suspend(std::coroutine_handle<> h) noexcept {
        if (m_notify->set_handle(h)) {
            return false;
        }
        if (m_count != 0) {
            remove_timer(m_timer_id);
        }
        m_timer_id = run_on_delay(m_delay_ms, [weak = this->weak()] () {
            auto p = weak.lock();
            if (p) {
                p->timeout();
            }
        });
        m_count ++;
        return true;
    }

    T await_resume() {
        if constexpr (std::is_void_v<T>) {
            m_notify->get();
        } else {
            return m_notify->get();
        }
    }

private:
    const int m_delay_ms;
    std::shared_ptr<TimeoutNotify<T>> m_notify =
        std::make_shared<TimeoutNotify<T>>();
    int m_timer_id = 0;
    int m_count = 0;
};


}

#endif
